package com.example.service.Impl;

import com.example.entity.user.Account;
import com.example.mapper.UserMapper;
import com.example.service.AuthorizeService;
import jakarta.annotation.Resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.mail.MailException;
import org.springframework.mail.MailSender;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.Optional;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class AuthorizeServiceImpl implements AuthorizeService {
    @Value("${spring.mail.username}")
    String from;
    @Resource
    UserMapper mapper;
    @Resource
    MailSender mailSender;

    @Resource
    StringRedisTemplate template; // 不能命名为redisTemplate，因为redisTemplate是SpringBoot自动配置的，如果命名为redisTemplate，则会覆盖SpringBoot自动配置的redisTemplate

    BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if (username == null) {
            throw new UsernameNotFoundException("用户名不能为空");
        }
        Account account = mapper.findAccountByNameOrEmail(username);
        if (account == null)
            throw new UsernameNotFoundException("用户名或密码错误");
        return User
                .withUsername(account.getUsername())
                .password(account.getPassword())
                .roles("user")
                .build();
    }
    /**
     * 1. 生成验证码
     * 2. 把邮箱和对应的验证码直接发送到Redis里面（过期时间三分钟，如果此时重写要求发送邮件，只要剩余事件低于两分钟，就可以重新发一次，重复此流程）
     * 3. 发送验证码到指定用户邮箱
     * 4. 如果发送失败，则删除Redis里面的验证码
     * 5. 用户在注册时，再从Redis里面获取验证码（对应键值对），然后进行比对
     */
    @Override
    public String sendValidateEmail(String email, String sessionId, boolean hasAccount) {
        String key = "email:" + sessionId + ":" + email + ":" + hasAccount; // 存放sessionId和邮箱的键值对,避免用户使用A邮箱获得验证码，然后使用B邮箱注册
        if (Boolean.TRUE.equals(template.hasKey(key))) {
            // 如果redis中存在该键值对，则判断剩余时间是否大于两分钟，大于则提示验证码已发送...
            Long expire = Optional.ofNullable(template.getExpire(key, TimeUnit.SECONDS)).orElse(0L);
            if (expire > 120) return "验证码已发送，请注意查收";
        }
        Account account = mapper.findAccountByNameOrEmail(email);
        if (hasAccount && account == null) return "没有此邮箱地址的账户";
        if( !hasAccount && account != null) return "此邮箱已被注册";
        Random random = new Random();
        int code = random.nextInt(899999) + 100000;
        SimpleMailMessage message = new SimpleMailMessage();
        message.setFrom(from);
        message.setTo(email);
        message.setSubject("验证码");
        message.setText("你的验证码为" + code);
        try {
            mailSender.send(message);
            template.opsForValue().set(key, String.valueOf(code), 3, TimeUnit.MINUTES); // redis中存放验证码，并设置过期时间3分钟
            return null;
        }catch (MailException e) {
            e.printStackTrace();
            return "验证码发送失败,请稍后再尝试";
        }
    }

    @Override
    public String validateAndRegister(String username, String password, String email, String code, String sessionId) {
        String key = "email:" + sessionId + ":" + email + ":false";
        if (Boolean.TRUE.equals(template.hasKey(key))) {
            String s = template.opsForValue().get(key);
            if (s == null) return "验证码已过期,请重新请求";
            if (s.equals(code)){
                Account account = mapper.findAccountByNameOrEmail(username);
                if (account != null) return "用户名已存在";
                template.delete(key); // 验证码验证成功后，删除redis中的验证码
                password = encoder.encode(password);
                if (mapper.createAccount(username, password, email) > 0) {
                    return null;
                }else {
                    return "注册失败,请稍后再试";
                }
            }else {
                return "验证码错误,请重新输入";
            }
        }else {
            return "验证码无效,请先请求验证码";
        }
    }
    // 忘记密码验证码请求处理
    @Override
    public String validateAndForgot(String email, String code, String sessionId) {
        String key = "email:" + sessionId + ":" + email + ":true";
        if (Boolean.TRUE.equals(template.hasKey(key))) {
            String s = template.opsForValue().get(key);
            if (s == null) return "验证码已过期，请重新请求";
            if(s.equals(code)) {
                template.delete(key);
                return null;
            }else {
                return "验证码错误，请重新输入";
            }
        }else {
            return "验证码无效，请先请求验证码";
        }
    }

    @Override
    public boolean forgotPassword(String password, String email) {
        password = encoder.encode(password);
        return mapper.forgotPasswordByEmail(password, email) > 0;
    }
}
